bitkeeper revision 1.1098.2.1 (4107d792-8oUXilcPgo1Fl8qnr9ZsQ)
authorach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Wed, 28 Jul 2004 16:42:58 +0000 (16:42 +0000)
committerach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Wed, 28 Jul 2004 16:42:58 +0000 (16:42 +0000)
large changes to pdb

xen/arch/x86/pdb-linux.c
xen/arch/x86/pdb-stub.c
xen/common/debug-linux.c
xen/common/debug.c
xen/include/asm-x86/pdb.h

index fd0fc5ed784d3e040763b6351404b1eb7187c494..965924f47aca0c86d7311469cd8dc5bcfaf32c3c 100644 (file)
  * linux & i386 dependent code. bleech.
  */
 
+#include <xen/slab.h>
 #include <asm/pdb.h>
 
+extern unsigned char pdb_x86_bkpt;
+extern int pdb_x86_bkpt_length;
+
 /* offset to the first instruction in the linux system call code
    where we can safely set a breakpoint */
 unsigned int pdb_linux_syscall_enter_bkpt_offset = 20;
@@ -92,9 +96,25 @@ pdb_linux_syscall_exit_bkpt (struct pt_regs *regs, struct pdb_context *pdb_ctx)
        debugger when re-entering user space */
     pdb_system_call_next_addr = *(unsigned long *)(regs->esp + 
                                                 pdb_linux_syscall_eip_offset);
-    pdb_linux_get_values (&pdb_system_call_leave_instr, 1, 
-                         pdb_system_call_next_addr,
-                         pdb_ctx->process, pdb_ctx->ptbr);
-    pdb_linux_set_values ("cc", 1, pdb_system_call_next_addr,
-                         pdb_ctx->process, pdb_ctx->ptbr);
+
+    /* set a breakpoint when we exit */
+    {
+        pdb_bwcpoint_p bwc = (pdb_bwcpoint_p) kmalloc(sizeof(pdb_bwcpoint_t));
+
+       bwc->address = pdb_system_call_next_addr;
+       bwc->length = 1;
+       bwc->type = PDB_BP_SOFTWARE;
+       bwc->user_type = PDB_BP_SOFTWARE;
+       bwc->original = pdb_system_call_leave_instr;
+       memcpy (&bwc->context, pdb_ctx, sizeof(pdb_context_t));
+
+       /* this is always in a process context */
+       pdb_read_memory (pdb_system_call_next_addr, 1, 
+                        &pdb_system_call_leave_instr,
+                        (pdb_context_p) pdb_ctx);
+       pdb_write_memory (pdb_system_call_next_addr, pdb_x86_bkpt_length,
+                         &pdb_x86_bkpt, (pdb_context_p) pdb_ctx);
+
+       pdb_bwc_list_add (bwc);
+    }
 }
index 51cb898dc52f0c574d42ad3dc8a02c3b7737504e..c4ebf74a3d34664f7cf734f5b659bac5252b8c7f 100644 (file)
 #include <xen/serial.h>
 #include <xen/softirq.h>
 
-#define PDB_DEBUG_TRACE
-#ifdef PDB_DEBUG_TRACE
-#define TRC(_x) _x
-#else
-#define TRC(_x)
-#endif
+int pdb_trace = 1;                                 /* debugging the debugger */
 
 #define DEBUG_EXCEPTION     0x01
 #define BREAKPT_EXCEPTION   0x03
 #define PDB_LIVE_EXCEPTION  0x58
 #define KEYPRESS_EXCEPTION  0x88
 
-#define BUFMAX 400
-
 static const char hexchars[] = "0123456789abcdef";
 
-static int remote_debug;
-
 #define PDB_BUFMAX 1024
 static char pdb_in_buffer[PDB_BUFMAX];
 static char pdb_out_buffer[PDB_BUFMAX];
-static char pdb_buffer[PDB_BUFMAX];
 static int  pdb_in_buffer_ptr;
 static unsigned char  pdb_in_checksum;
 static unsigned char  pdb_xmit_checksum;
 
-struct pdb_context pdb_ctx;
+void pdb_put_packet (unsigned char *buffer, int ack);
+
+pdb_context_t pdb_ctx;
 int pdb_continue_thread = 0;
 int pdb_general_thread = 0;
 
-void pdb_put_packet (unsigned char *buffer, int ack);
-void pdb_bkpt_check (u_char *buffer, int length,
-                    unsigned long cr3, unsigned long addr);
+
+enum pdb_bwc_page_action
+{
+  PDB_BWC_PAGE_ACCESS_SET,
+  PDB_BWC_PAGE_ACCESS_CLEAR,
+  PDB_BWC_PAGE_WRITE_SET,
+  PDB_BWC_PAGE_WRITE_CLEAR,
+  PDB_BWC_PAGE_READ_SET,
+  PDB_BWC_PAGE_READ_CLEAR,
+};
+static char *pdb_bwc_page_action_s[] =
+  { "ac set", "ac clr", "wr set", "wr clr", "rd set", "rd cler" };
+int pdb_bwc_page (int action, unsigned long addr, int length, 
+                 pdb_context_p ctx, int offset, void *s);
+
+enum pdb_visit_page_action
+{
+  PDB_VISIT_PAGE_XEN_READ,
+  PDB_VISIT_PAGE_XEN_WRITE,
+  PDB_VISIT_PAGE_DOMAIN_READ,
+  PDB_VISIT_PAGE_DOMAIN_WRITE,
+  PDB_VISIT_PAGE_PROCESS_READ,
+  PDB_VISIT_PAGE_PROCESS_WRITE,
+};
+static char *pdb_visit_page_action_s[] =
+  { "xen rd", "xen wr", "dom rd", "dom wr", "proc rd", "proc wr" };
+
+int pdb_visit_page (int action, unsigned long addr, int length,
+                    pdb_context_p ctx, int offset, void *s);
 
 int pdb_initialized = 0;
 int pdb_page_fault_possible = 0;
@@ -69,6 +87,12 @@ unsigned char pdb_system_call_leave_instr = 0;        /* original next instr */
 unsigned long pdb_system_call_next_addr = 0;         /* instr after int 0x80 */
 unsigned long pdb_system_call_eflags_addr = 0;      /* saved eflags on stack */
 
+unsigned char pdb_x86_bkpt = 0xcc;
+unsigned int  pdb_x86_bkpt_length = 1;
+
+/***********************************************************************/
+/***********************************************************************/
+
 static inline void pdb_put_char(unsigned char c)
 {
     serial_putc(pdb_serhnd, c);
@@ -79,18 +103,136 @@ static inline unsigned char pdb_get_char(void)
     return serial_getc(pdb_serhnd);
 }
 
+/***********************************************************************/
+/***********************************************************************/
+
+/*
+ * Prototype for function to process each page.  This function is called
+ * once per page.
+ *
+ * action  : function specific
+ * address : first byte of this page
+ * length  : number of bytes to process on this page
+ * offset  : number of bytes processed so far. can be used as
+ *           an index into data.
+ * data    : function specific.
+ */
+
+typedef int (pdb_invoke_ftype) (int action, unsigned long address, int length, 
+                               pdb_context_p ctx, int offset, void *data);
+
+typedef struct pdb_invoke_args
+{
+  pdb_context_p context;
+  unsigned long address;
+  int length;
+  int action;
+  void *data;
+} pdb_invoke_args_t, * pdb_invoke_args_p;
+
+
+/*
+ * call a particular function once per page given an address & length
+ */
+
 int
-get_char (char *addr)
+pdb_invoke(pdb_invoke_ftype *function, pdb_invoke_args_p args)
+{
+  int remaining;
+  int bytes = 0;
+  int length = args->length;
+  unsigned long address = args->address;
+
+  while ((remaining = (address + length - 1) - (address | (PAGE_SIZE - 1))) > 0)
+  {
+    bytes += (function)(args->action, address, length - remaining,
+                       args->context, address - args->address, args->data);
+    length = remaining;
+    address = (address | (PAGE_SIZE - 1)) + 1;
+  }
+  bytes += (function)(args->action, address, length,
+                      args->context, address - args->address, args->data);
+  return bytes;
+}
+
+
+/***********************************************************************/
+/***********************************************************************/
+
+/* BWC List Support: breakpoints, watchpoints, and catchpoints */
+
+char *pdb_bwcpoint_type_s[] =                      /* enum pdb_bwcpoint_type */
+  { "BP_SOFTWARE", "BP_HARDWARE", "WP_WRITE", "WP_READ", "WP_ACCESS" };
+
+int pdb_set_watchpoint (pdb_bwcpoint_p bwc); 
+int pdb_clear_watchpoint (pdb_bwcpoint_p bwc);
+
+struct list_head pdb_bwc_list = LIST_HEAD_INIT(pdb_bwc_list);
+
+void
+pdb_bwc_list_add (pdb_bwcpoint_p bwc)
+{
+  list_add_tail(&bwc->list, &pdb_bwc_list);
+}
+
+void
+pdb_bwc_list_remove (pdb_bwcpoint_p bwc)
+{
+  list_del(&bwc->list);
+}
+
+pdb_bwcpoint_p
+pdb_bwc_list_search (unsigned long address, int length, pdb_context_p ctx)
+{
+  struct list_head *ptr;
+
+  list_for_each (ptr, &pdb_bwc_list)
+  {
+    pdb_bwcpoint_p bwc = list_entry(ptr, pdb_bwcpoint_t, list);
+
+    if (bwc->address == address &&
+        bwc->length  == length)
+    {
+      return bwc;
+    }
+  }
+  return (pdb_bwcpoint_p) 0;
+}
+
+pdb_bwcpoint_p
+pdb_bwcpoint_search (unsigned long cr3, unsigned long address)
 {
-    return *addr;
+  pdb_context_t ctx;
+
+  ctx.ptbr = cr3;
+  return pdb_bwc_list_search (address, pdb_x86_bkpt_length, &ctx);
 }
 
 void
-set_char (char *addr, int val)
+pdb_bwc_print (pdb_bwcpoint_p bwc)
 {
-    *addr = val;
+    printk ("address: 0x%08lx, length: 0x%02x, type: 0x%x %s", 
+           bwc->address, bwc->length,
+           bwc->type, pdb_bwcpoint_type_s[bwc->type]);
 }
 
+void
+pdb_bwc_print_list ()
+{
+  struct list_head *ptr;
+  int counter = 0;
+
+  list_for_each (ptr, &pdb_bwc_list)
+  {
+    pdb_bwcpoint_p bwc = list_entry(ptr, pdb_bwcpoint_t, list);
+    printk ("  [%02d]  ", counter);   pdb_bwc_print(bwc);   printk ("\n");
+    counter++;
+  }
+}
+
+/***********************************************************************/
+/***********************************************************************/
+
 void
 pdb_process_query (char *ptr)
 {
@@ -100,144 +242,230 @@ pdb_process_query (char *ptr)
     }
     else if (strcmp(ptr, "fThreadInfo") == 0)
     {
-#ifdef PDB_PAST
-        struct domain *p;
-        u_long flags;
-#endif /* PDB_PAST */
+        int buf_idx = 0;
 
+       pdb_out_buffer[buf_idx++] = 'l';
+       pdb_out_buffer[buf_idx++] = 0;
+    }
+    else if (strcmp(ptr, "sThreadInfo") == 0)
+    {
         int buf_idx = 0;
 
        pdb_out_buffer[buf_idx++] = 'l';
        pdb_out_buffer[buf_idx++] = 0;
+    }
+    else if (strncmp(ptr, "ThreadExtraInfo,", 16) == 0)
+    {
+        int thread = 0;
+       char *message = "foobar ?";
 
-#ifdef PDB_PAST
-       switch (pdb_level)
-       {
-       case PDB_LVL_XEN:                        /* return a list of domains */
+       ptr += 16;
+        if (hexToInt (&ptr, &thread))
        {
-           int count = 0;
+            mem2hex (message, pdb_out_buffer, strlen(message) + 1);
+       }
+
+#ifdef PDB_FUTURE
+      {
+       char string[task_struct_comm_length];
+
+       string[0] = 0;
+       pdb_linux_process_details (cr3, pid, string);
+       printk (" (%s)", string);
+      }
+#endif /* PDB_FUTURE*/
+    }
+    else if (strcmp(ptr, "Offsets") == 0)
+    {
+        /* empty string */
+    }
+    else if (strncmp(ptr, "Symbol", 6) == 0)
+    {
+        strcpy (pdb_out_buffer, "OK");
+    }
+    else
+    {
+        printk("pdb: error, unknown query [%s]\n", ptr);
+    }
+}
 
-           read_lock_irqsave (&tasklist_lock, flags);
+void
+pdb_process_z (int onoff, char *ptr)
+{
+    int type = *(ptr++) - '0';
+    int length;
+    unsigned long addr;
+    char *error = "E01";                                     /* syntax error */
+
+    /* try to read ',addr,length' */
+    if (   *(ptr++) == ','
+       && hexToInt(&ptr, (int *)&addr)
+       && *(ptr++) == ','
+       && hexToInt(&ptr, &length))
+    {
+       error = "OK";
 
-           pdb_out_buffer[buf_idx++] = 'm';
-           for_each_domain ( p )
+       switch (type)
+       {
+       case PDB_BP_SOFTWARE:
+       case PDB_BP_HARDWARE:
+       {
+           if (onoff == 1)
            {
-               domid_t domain = p->domain + PDB_ID_OFFSET;
+               pdb_bwcpoint_p bwc = (pdb_bwcpoint_p) kmalloc(sizeof(pdb_bwcpoint_t));
+
+               bwc->address = addr;
+               bwc->length = pdb_x86_bkpt_length;
+               bwc->type = PDB_BP_SOFTWARE;
+               bwc->user_type = type;
+               memcpy (&bwc->context, &pdb_ctx, sizeof(pdb_context_t));
 
-               if (count > 0)
+               if (length != pdb_x86_bkpt_length)
                {
-                   pdb_out_buffer[buf_idx++] = ',';
+                   printk("pdb warning: x86 bkpt length should be 1\n");
                }
-               if (domain > 15)
+
+               pdb_set_breakpoint (bwc);
+           }
+           else
+           {
+               pdb_clear_breakpoint (addr, pdb_x86_bkpt_length, &pdb_ctx);
+               pdb_bwcpoint_p bwc = pdb_bwc_list_search (addr, 1, &pdb_ctx);
+
+               if (bwc == 0)
                {
-                   pdb_out_buffer[buf_idx++] = hexchars[domain >> 4];
+                   error = "E03";                   /* breakpoint not found */
+                   break;
                }
-               pdb_out_buffer[buf_idx++] = hexchars[domain % 16];
-               count++;
-           }
-           pdb_out_buffer[buf_idx++] = 0;
 
-           read_unlock_irqrestore(&tasklist_lock, flags);
+               pdb_write_memory (addr, 1, &bwc->original, &pdb_ctx);
+
+               pdb_bwc_list_remove (bwc);
+           }
            break;
        }
-       case PDB_LVL_GUESTOS:                  /* return a list of processes */
+       case PDB_WP_WRITE:
+       case PDB_WP_READ:
+       case PDB_WP_ACCESS:
        {
-           int foobar[20];
-           int loop, total;
+           if (onoff == 1)
+           {
+               pdb_bwcpoint_p bwc = (pdb_bwcpoint_p) kmalloc(sizeof(pdb_bwcpoint_t));
+
+               bwc->address = addr;
+               bwc->length = length;
+               bwc->type = type;
+               bwc->user_type = type;
+               memcpy (&bwc->context, &pdb_ctx, sizeof(pdb_context_t));
 
-                                                       /* this cr3 is wrong! */
-           total = pdb_linux_process_list(pdb_ctx[pdb_level].info_cr3,
-                                          foobar, 20);
+               pdb_set_watchpoint (bwc);
 
-           pdb_out_buffer[buf_idx++] = 'm';     
-           pdb_out_buffer[buf_idx++] = '1';              /* 1 is to go back */
-           for (loop = 0; loop < total; loop++)
+               pdb_bwc_list_add (bwc);
+           }
+           else
            {
-               int pid = foobar[loop] + PDB_ID_OFFSET;
+               pdb_bwcpoint_p bwc = pdb_bwc_list_search (addr, 1, &pdb_ctx);
 
-               pdb_out_buffer[buf_idx++] = ',';
-               if (pid > 15)
+               if (bwc == 0)
                {
-                   pdb_out_buffer[buf_idx++] = hexchars[pid >> 4];
+                   error = "E03";                   /* watchpoint not found */
+                   break;
                }
-               pdb_out_buffer[buf_idx++] = hexchars[pid % 16];
+
+               pdb_clear_watchpoint (bwc);
+
+               pdb_bwc_list_remove (bwc);
            }
-           pdb_out_buffer[buf_idx++] = 0;
            break;
        }
-       case PDB_LVL_PROCESS:                                     /* hmmm... */
+       default:
        {
-           pdb_out_buffer[buf_idx++] = 'm';
-           pdb_out_buffer[buf_idx++] = '1';              /* 1 is to go back */
+           printk ("pdb error: unknown Z command [%c]\n", type);
+           error = "E02";                                   /* syntax error */
            break;
        }
-       default:
-           break;
        }
-#endif /* PDB_PAST */
-
     }
-    else if (strcmp(ptr, "sThreadInfo") == 0)
-    {
-        int buf_idx = 0;
 
-       pdb_out_buffer[buf_idx++] = 'l';
-       pdb_out_buffer[buf_idx++] = 0;
-    }
-    else if (strncmp(ptr, "ThreadExtraInfo,", 16) == 0)
+    if (error)                               /* return value, including okay */
     {
-        int thread = 0;
-       char *message = "foobar ?";
+       strcpy (pdb_out_buffer, error);
+    }
+}
 
-       ptr += 16;
-        if (hexToInt (&ptr, &thread))
+void
+pdb_process_pdb (char *ptr)
+{
+    unsigned long arg1, arg2;
+    char *error = "E01";                                     /* syntax error */
+    char command = *(ptr++);
+
+    switch (command)
+    {
+    case 'c':                                             /* set pdb context */
+    case 'C':
+    {
+        /* try to read two hex arguments ':arg1,arg2 */
+        if (   *(ptr++) == ':'
+           && hexToInt(&ptr, (int *)&arg1)
+           && *(ptr++) == ','
+           && hexToInt(&ptr, (int *)&arg2))
        {
-            mem2hex (message, pdb_out_buffer, strlen(message) + 1);
+           printk ("pdb: set context: domain:0x%lx process:0x%lx\n", 
+                   arg1, arg2);
+           error = "OK";
        }
 
-#ifdef PDB_PAST
-        int thread = 0;
-       char message[16];
-       struct domain *p;
-
-       p = find_domain_by_id(pdb_ctx[pdb_level].info);
-       strncpy (message, p->name, 16);
-       put_domain(p);
-
-       ptr += 16;
-        if (hexToInt (&ptr, &thread))
+        pdb_ctx.domain  = arg1;
+       pdb_ctx.process = arg2;
+       pdb_ctx.valid   = 1;
+       break;
+    }
+    case 't':                                          /* enable pdb tracing */
+    case 'T':
+    {
+        /* read the trace level */
+        if (   *(ptr++) == ':'
+           && hexToInt(&ptr, (int *)&pdb_trace))
        {
-            mem2hex ((char *)message, pdb_out_buffer, strlen(message) + 1);
+           printk ("pdb: set trace level: 0x%x\n", pdb_trace);
+           error = "OK";
        }
-#endif /* PDB_PAST */
-
-#ifdef PDB_FUTURE
-      {
-       char string[task_struct_comm_length];
-
-       string[0] = 0;
-       pdb_linux_process_details (cr3, pid, string);
-       printk (" (%s)", string);
-      }
-#endif /* PDB_FUTURE*/
-
+       break;
     }
-    else if (strcmp(ptr, "Offsets") == 0)
+    case 'd':
+    case 'D':                                              /* dump pdb state */
     {
-        /* empty string */
+        printk ("----------\n");
+        printk ("pdb trace : %2d 0x%02x\n", pdb_trace, pdb_trace);
+        printk ("pdb ctx domain  : %4d 0x%04x\n",
+               pdb_ctx.domain, pdb_ctx.domain);
+        printk ("        process : %4d 0x%04x\n",
+               pdb_ctx.process, pdb_ctx.process);
+        printk ("        sys call: %4d 0x%04x\n",
+               pdb_ctx.system_call, pdb_ctx.system_call);
+        printk ("bwc list:\n");
+       pdb_bwc_print_list ();
+        printk ("----------\n");
+       error = "OK";
+       break;
     }
-    else if (strncmp(ptr, "Symbol", 6) == 0)
+    default:
     {
-        strcpy (pdb_out_buffer, "OK");
+        printk ("pdb error: unknown pdb dot command [%c]\n", command);
+       error = "E02";                                       /* syntax error */
+       break;
     }
-    else
+    }
+
+    if (error)                               /* return value, including okay */
     {
-        printk("pdb: error, unknown query [%s]\n", ptr);
+       strcpy (pdb_out_buffer, error);
     }
 }
 
 void
-pdb_x86_to_gdb_regs (char *buffer, struct pt_regs *regs)
+pdb_read_regs (char *buffer, struct pt_regs *regs)
 {
     int idx = 0;
 
@@ -276,7 +504,7 @@ pdb_x86_to_gdb_regs (char *buffer, struct pt_regs *regs)
 
 /* at this point we allow any register to be changed, caveat emptor */
 void
-pdb_gdb_to_x86_regs (struct pt_regs *regs, char *buffer)
+pdb_write_regs (struct pt_regs *regs, char *buffer)
 {
     hex2mem(buffer, (char *)&regs->eax, sizeof(regs->eax));
     buffer += sizeof(regs->eax) * 2;
@@ -320,7 +548,7 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
     int ack = 1;                           /* wait for ack in pdb_put_packet */
     int go = 0;
 
-    TRC(printf("pdb: [%s]\n", ptr));
+    PDBTRC(1,printk("pdb: [%s]\n", ptr));
 
     pdb_out_buffer[0] = 0;
 
@@ -386,8 +614,8 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
        }
 
        pdb_ctx.valid = 0;
-       TRC(printk ("pdb change context (dom:%d, proc:%d) now 0x%lx\n",
-                   pdb_ctx.domain, pdb_ctx.process, pdb_ctx.ptbr));
+       PDBTRC(1,printk ("pdb change context (dom:%d, proc:%d) now 0x%lx\n",
+                     pdb_ctx.domain, pdb_ctx.process, pdb_ctx.ptbr));
     }
 
     switch (*ptr++)
@@ -404,16 +632,13 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
         if ( pdb_system_call_eflags_addr != 0 )
        {
            unsigned long eflags;
-           char eflags_buf[sizeof(eflags)*2];       /* STUPID STUPID STUPID */
 
-           pdb_linux_get_values((u_char*)&eflags, sizeof(eflags), 
-                                pdb_system_call_eflags_addr
-                                pdb_ctx.process, pdb_ctx.ptbr);
+           /* this is always in a process context */
+           pdb_read_memory (pdb_system_call_eflags_addr, sizeof(eflags)
+                            (u_char *)&eflags, &pdb_ctx);
            eflags |= X86_EFLAGS_TF;
-           mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags)); 
-           pdb_linux_set_values(eflags_buf, sizeof(eflags),
-                                pdb_system_call_eflags_addr,
-                                pdb_ctx.process, pdb_ctx.ptbr);
+           pdb_write_memory (pdb_system_call_eflags_addr, sizeof(eflags), 
+                             (u_char *)&eflags, &pdb_ctx);
        }
 
         regs->eflags |= X86_EFLAGS_TF;
@@ -427,16 +652,13 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
         if ( pdb_system_call_eflags_addr != 0 )
        {
            unsigned long eflags;
-           char eflags_buf[sizeof(eflags)*2];       /* STUPID STUPID STUPID */
 
-           pdb_linux_get_values((u_char*)&eflags, sizeof(eflags), 
-                                pdb_system_call_eflags_addr
-                                pdb_ctx.process, pdb_ctx.ptbr);
+           /* this is always in a process context */
+           pdb_read_memory (pdb_system_call_eflags_addr, sizeof(eflags)
+                            (u_char *)&eflags, &pdb_ctx);
            eflags &= ~X86_EFLAGS_TF;
-           mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags)); 
-           pdb_linux_set_values(eflags_buf, sizeof(eflags),
-                                pdb_system_call_eflags_addr,
-                                pdb_ctx.process, pdb_ctx.ptbr);
+           pdb_write_memory (pdb_system_call_eflags_addr, sizeof(eflags), 
+                             (u_char *)&eflags, &pdb_ctx);
        }
 
         regs->eflags &= ~X86_EFLAGS_TF;
@@ -444,19 +666,18 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
         /* not reached */
     }
     case 'd':
-        remote_debug = !(remote_debug);                 /* toggle debug flag */
         break;
     case 'D':                                                      /* detach */
-        return go;
-        /* not reached */
+        go = 1;
+        break;
     case 'g':                       /* return the value of the CPU registers */
     {
-        pdb_x86_to_gdb_regs (pdb_out_buffer, regs);
+        pdb_read_regs (pdb_out_buffer, regs);
         break;
     }
     case 'G':              /* set the value of the CPU registers - return OK */
     {
-        pdb_gdb_to_x86_regs (regs, ptr);
+        pdb_write_regs (regs, ptr);
         break;
     }
     case 'H':
@@ -509,24 +730,20 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
                 {
                     ptr = 0;
 
-                   pdb_page_fault_possible = 1;
+                   pdb_page_fault_possible = 2;
                    pdb_page_fault = 0;
-                   if (addr >= PAGE_OFFSET)
-                   {
-                        mem2hex ((char *) addr, pdb_out_buffer, length); 
-                   }
-                   else if (pdb_ctx.process != -1)
-                   {
-                       pdb_linux_get_values(pdb_buffer, length, addr, 
-                                            pdb_ctx.process, pdb_ctx.ptbr);
-                        mem2hex (pdb_buffer, pdb_out_buffer, length); 
-                   }
-                    else
-                    {
-                       pdb_get_values (pdb_buffer, length, 
-                                       pdb_ctx.ptbr, addr);
-                        mem2hex (pdb_buffer, pdb_out_buffer, length);
-                    }
+
+           {
+               u_char *buffer = (u_char *) kmalloc (length);
+               if (!buffer)
+               {
+                   printk ("pdb error: kmalloc failure\n");
+                   break;
+               }
+               pdb_read_memory (addr, length, buffer, &pdb_ctx);
+               mem2hex (buffer, pdb_out_buffer, length); 
+               kfree(buffer);
+           }
 
                    pdb_page_fault_possible = 0;
                    if (pdb_page_fault)
@@ -546,44 +763,39 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
     case 'M':
     {
         /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
-        if (hexToInt (&ptr, (int *)&addr))
-            if (*(ptr++) == ',')
-                if (hexToInt (&ptr, &length))
-                    if (*(ptr++) == ':')
-                    {
-
-                       pdb_page_fault_possible = 1;
-                       pdb_page_fault = 0;
-                       if (addr >= PAGE_OFFSET)
-                       {
-                           hex2mem (ptr, (char *)addr, length);
-                           pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
-                       }
-                       else if (pdb_ctx.process != -1)
-                       {
-                           pdb_linux_set_values(ptr, length, addr,
-                                                pdb_ctx.process, 
-                                                pdb_ctx.ptbr);
-                           pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
-                       }
-                       else
-                       {
-                           pdb_set_values (ptr, length,
-                                           pdb_ctx.ptbr, addr);
-                           pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
-                       }
-                       pdb_page_fault_possible = 0;
-                        if (pdb_page_fault)
-                        {
-                            strcpy (pdb_out_buffer, "E03");
-                        }
-                        else
-                        {
-                            strcpy (pdb_out_buffer, "OK");
-                        }
-
-                        ptr = 0;
-                    }
+        if (   hexToInt (&ptr, (int *)&addr)
+           && *(ptr++) == ','
+            && hexToInt (&ptr, &length)
+           && *(ptr++) == ':')
+       {
+           pdb_page_fault_possible = 3;
+           pdb_page_fault = 0;
+
+           {
+               u_char *buffer = (u_char *) kmalloc (length);
+               if (!buffer)
+               {
+                   printk ("pdb error: kmalloc failure\n");
+                   break;
+               }
+               hex2mem (ptr, buffer, length);
+               pdb_write_memory (addr, length, buffer, &pdb_ctx);
+               kfree(buffer);
+           }
+
+           pdb_page_fault_possible = 0;
+           if (pdb_page_fault)
+           {
+               strcpy (pdb_out_buffer, "E03");
+           }
+           else
+           {
+               strcpy (pdb_out_buffer, "OK");
+           }
+
+           ptr = 0;
+       }
+
         if (ptr)
         {
             strcpy (pdb_out_buffer, "E02");
@@ -597,59 +809,29 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
         if (hexToInt (&ptr, &id))
         {
            strcpy (pdb_out_buffer, "E00");
-
-#ifdef PDB_PAST
-
-           switch (pdb_level)                             /* previous level */
-           {
-               case PDB_LVL_XEN:
-               {
-                   struct domain *p;
-                   id -= PDB_ID_OFFSET;
-                   if ( (p = find_domain_by_id(id)) == NULL)
-                       strcpy (pdb_out_buffer, "E00");
-                   else
-                       strcpy (pdb_out_buffer, "OK");
-                   put_domain(p);
-
-                   pdb_level = PDB_LVL_GUESTOS;
-                   pdb_ctx[pdb_level].ctrl = id;
-                   pdb_ctx[pdb_level].info = id;
-                   break;
-               }
-               case PDB_LVL_GUESTOS:
-               {
-                   if (pdb_level == -1)
-                   {
-                       pdb_level = PDB_LVL_XEN;
-                   }
-                   else
-                   {
-                       pdb_level = PDB_LVL_PROCESS;
-                       pdb_ctx[pdb_level].ctrl = id;
-                       pdb_ctx[pdb_level].info = id;
-                   }
-                   break;
-               }
-               case PDB_LVL_PROCESS:
-               {
-                   if (pdb_level == -1)
-                   {
-                       pdb_level = PDB_LVL_GUESTOS;
-                   }
-                   break;
-               }
-               default:
-               {
-                   printk ("pdb internal error: invalid level [%d]\n", 
-                           pdb_level);
-               }
-           }
-
-#endif /* PDB_PAST */
         }
         break;
     }
+    case 'Z':                                                         /* set */
+    {
+        pdb_process_z (1, ptr);
+       break;
+    }
+    case 'z':                                                       /* clear */
+    {
+        pdb_process_z (0, ptr);
+       break;
+    }
+    case '.':                                     /* pdb specific extensions */
+    {
+        pdb_process_pdb (ptr);
+       break;
+    }
+    default:
+    {
+        PDBTRC(1,printk ("pdb warning: ignoring unknown command.\n"));
+       break;
+    }
     }
 
 exit:
@@ -712,8 +894,8 @@ int pdb_serial_input(u_char c, struct pt_regs *regs)
        if (pdb_in_checksum != pdb_xmit_checksum) 
        {
            pdb_put_char('-');                           /* checksum failure */
-           printk ("checksum failure [%s.%02x.%02x]\n", pdb_in_buffer,
-                   pdb_in_checksum, pdb_xmit_checksum);
+           printk ("pdb error: checksum failure [%s.%02x.%02x]\n",
+                   pdb_in_buffer, pdb_in_checksum, pdb_xmit_checksum);
        }
        else 
        {
@@ -738,6 +920,9 @@ int pdb_serial_input(u_char c, struct pt_regs *regs)
     return out;
 }
 
+/***********************************************************************/
+/***********************************************************************/
+
 int hex(char ch)
 {
     if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
@@ -759,7 +944,8 @@ mem2hex (mem, buf, count)
 
     for (i = 0; i < count; i++)
     {
-        ch = get_char (mem++);
+        ch = *mem;
+       mem ++;
         *buf++ = hexchars[ch >> 4];
         *buf++ = hexchars[ch % 16];
     }
@@ -782,7 +968,8 @@ hex2mem (buf, mem, count)
     {
         ch = hex (*buf++) << 4;
         ch = ch + hex (*buf++);
-        set_char (mem++, ch);
+        *mem = ch;
+       mem++;
     }
     return (mem);
 }
@@ -826,150 +1013,153 @@ hexToInt (char **ptr, int *intValue)
 /***********************************************************************/
 /***********************************************************************/
 
+/* READ / WRITE MEMORY */
+int pdb_change_page (u_char *buffer, int length,
+                    unsigned long cr3, unsigned long addr, int rw);
+int pdb_visit_memory (unsigned long addr, int length, unsigned char *data,
+                     pdb_context_p ctx, pdb_generic_action action);
 
-/*
- * Add a breakpoint to the list of known breakpoints.
- * For now there should only be two or three breakpoints so
- * we use a simple linked list.  In the future, maybe a red-black tree?
- */
-struct pdb_breakpoint breakpoints;
-
-void pdb_bkpt_add (unsigned long cr3, unsigned long address)
+int 
+pdb_read_memory (unsigned long addr, int length, unsigned char *data,
+                pdb_context_p ctx)
 {
-    struct pdb_breakpoint *bkpt = kmalloc(sizeof(*bkpt));
-    bkpt->cr3 = cr3;
-    bkpt->address = address;
-    list_add(&bkpt->list, &breakpoints.list);
+    return pdb_visit_memory (addr, length, data, ctx, __PDB_GET);
 }
 
-/*
- * Check to see of the breakpoint is in the list of known breakpoints 
- * Return 1 if it has been set, NULL otherwise.
- */
-struct pdb_breakpoint* pdb_bkpt_search (unsigned long cr3, 
-                                       unsigned long address)
+int
+pdb_write_memory (unsigned long addr, int length, unsigned char *data,
+                 pdb_context_p ctx)
 {
-    struct list_head *list_entry;
-    struct pdb_breakpoint *bkpt;
-
-    list_for_each(list_entry, &breakpoints.list)
-    {
-        bkpt = list_entry(list_entry, struct pdb_breakpoint, list);
-       if ( bkpt->cr3 == cr3 && bkpt->address == address )
-            return bkpt;
-    }
-
-    return NULL;
+    return pdb_visit_memory (addr, length, data, ctx, __PDB_SET);
 }
 
 /*
- * Remove a breakpoint to the list of known breakpoints.
- * Return 1 if the element was not found, otherwise 0.
+ * either read or write a block of memory 
  */
-int pdb_bkpt_remove (unsigned long cr3, unsigned long address)
+
+int
+pdb_visit_memory (unsigned long addr, int length, unsigned char *data,
+                 pdb_context_p ctx, pdb_generic_action action)
 {
-    struct list_head *list_entry;
-    struct pdb_breakpoint *bkpt;
+    int return_value;
+    pdb_invoke_args_t args;
 
-    list_for_each(list_entry, &breakpoints.list)
-    {
-        bkpt = list_entry(list_entry, struct pdb_breakpoint, list);
-       if ( bkpt->cr3 == cr3 && bkpt->address == address )
-       {
-            list_del(&bkpt->list);
-            kfree(bkpt);
-            return 0;
-       }
-    }
+    pdb_page_fault_possible = 4;
+    pdb_page_fault = 0;
 
-    return 1;
-}
+    args.context = ctx;
+    args.address = addr;
+    args.length = length;
+    args.data = data;
 
-/*
- * Check to see if a memory write is really gdb setting a breakpoint
- */
-void pdb_bkpt_check (u_char *buffer, int length,
-                    unsigned long cr3, unsigned long addr)
-{
-    if (length == 1 && buffer[0] == 'c' && buffer[1] == 'c')
+    if (addr >= PAGE_OFFSET)                                          /* Xen */
     {
-        /* inserting a new breakpoint */
-        pdb_bkpt_add(cr3, addr);
-        TRC(printk("pdb breakpoint detected at 0x%lx:0x%lx\n", cr3, addr));
+        args.action = (action == __PDB_GET) ? PDB_VISIT_PAGE_XEN_READ
+                                            : PDB_VISIT_PAGE_XEN_WRITE;
     }
-    else if ( pdb_bkpt_remove(cr3, addr) == 0 )
+    else if (pdb_ctx.process != -1)                               /* Process */
     {
-        /* removing a breakpoint */
-        TRC(printk("pdb breakpoint cleared at 0x%lx:0x%lx\n", cr3, addr));
+        args.action = (action == __PDB_GET) ? PDB_VISIT_PAGE_PROCESS_READ
+                                            : PDB_VISIT_PAGE_PROCESS_WRITE;
+    }
+    else                                                           /* Domain */
+    {
+        args.action = (action == __PDB_GET) ? PDB_VISIT_PAGE_DOMAIN_READ
+                                            : PDB_VISIT_PAGE_DOMAIN_WRITE;
     }
-}
-
-/***********************************************************************/
 
-int pdb_change_values(u_char *buffer, int length,
-                     unsigned long cr3, unsigned long addr, int rw);
-int pdb_change_values_one_page(u_char *buffer, int length,
-                              unsigned long cr3, unsigned long addr, int rw);
+    return_value = pdb_invoke (pdb_visit_page, &args);
 
-#define __PDB_GET_VAL 1
-#define __PDB_SET_VAL 2
+    pdb_page_fault_possible = 0;
+    if (pdb_page_fault || return_value < 0)
+    {
+        strcpy (pdb_out_buffer, "E03");
+    }
+  
+    return return_value;
+}
 
 /*
- * Set memory in a domain's address space
- * Set "length" bytes at "address" from "domain" to the values in "buffer".
- * Return the number of bytes set, 0 if there was a problem.
+ * either read or write a single page
  */
 
-int pdb_set_values(u_char *buffer, int length,
-                  unsigned long cr3, unsigned long addr)
+int 
+pdb_visit_page (int action, unsigned long addr, int length, 
+               pdb_context_p ctx, int offset, void *data)
 {
-    int count = pdb_change_values(buffer, length, cr3, addr, __PDB_SET_VAL);
-    return count;
+  int rval;
+  
+  PDBTRC(2,printk ("visit: %s [0x%08lx:%x] 0x%x (0x%p)\n",
+                  pdb_visit_page_action_s[action], 
+                  addr, length, offset, data));
+
+  switch (action)
+  {
+  case PDB_VISIT_PAGE_XEN_READ :
+  {
+      memcpy ((void *) data, (void *) addr, length);
+      rval = length;;
+      break;
+  }
+  case PDB_VISIT_PAGE_XEN_WRITE :
+  {
+      memcpy ((void *) addr, (void *) data, length);
+      rval = length;
+      break;
+  }
+  case PDB_VISIT_PAGE_DOMAIN_READ :
+  case PDB_VISIT_PAGE_DOMAIN_WRITE :
+  {
+      rval = pdb_change_page (data, length, ctx->ptbr, addr,
+               (action == PDB_VISIT_PAGE_DOMAIN_READ) ? __PDB_GET : __PDB_SET);
+      break;
+  }
+  case PDB_VISIT_PAGE_PROCESS_READ :
+  case PDB_VISIT_PAGE_PROCESS_WRITE :
+  {
+      u_char pdb_linux_visit_page(int pid, unsigned long cr3, unsigned long addr, int length, unsigned char *buffer, int action);
+
+      rval = pdb_linux_visit_page (ctx->process, ctx->ptbr, addr, length, data,
+              (action == PDB_VISIT_PAGE_PROCESS_READ) ? __PDB_GET : __PDB_SET);
+      break;
+  }
+  default :
+  {
+      printk ("pdb error: unknown visit page action [%d]\n", action);
+      break;
+  }
+  }
+
+  return 1;
 }
 
-/*
- * Read memory from a domain's address space.
- * Fetch "length" bytes at "address" from "domain" into "buffer".
- * Return the number of bytes read, 0 if there was a problem.
- */
+/**************************************/
+/**************************************/
 
-int pdb_get_values(u_char *buffer, int length,
-                  unsigned long cr3, unsigned long addr)
+int
+pdb_read_page(u_char *buffer, int length,
+               unsigned long cr3, unsigned long addr)
 {
-  return pdb_change_values(buffer, length, cr3, addr, __PDB_GET_VAL);
+    return pdb_change_page(buffer, length, cr3, addr, __PDB_GET);
 }
 
-/*
- * Read or write memory in an address space
- */
-int pdb_change_values(u_char *buffer, int length,
-                     unsigned long cr3, unsigned long addr, int rw)
+int
+pdb_write_page(u_char *buffer, int length,
+              unsigned long cr3, unsigned long addr)
 {
-    int remaining;                /* number of bytes to touch past this page */
-    int bytes = 0;
-
-    while ( (remaining = (addr + length - 1) - (addr | (PAGE_SIZE - 1))) > 0)
-    {
-        bytes += pdb_change_values_one_page(buffer, length - remaining, 
-                                           cr3, addr, rw);
-       buffer = buffer + (2 * (length - remaining));
-       length = remaining;
-       addr = (addr | (PAGE_SIZE - 1)) + 1;
-    }
-
-    bytes += pdb_change_values_one_page(buffer, length, cr3, addr, rw);
-    return bytes;
+    return pdb_change_page(buffer, length, cr3, addr, __PDB_SET);
 }
 
 /*
- * Change memory in a process' address space in one page
+ * Change memory in one page of an address space.
  * Read or write "length" bytes at "address" into/from "buffer"
  * from the virtual address space referenced by "cr3".
  * Return the number of bytes read, 0 if there was a problem.
  */
 
-int pdb_change_values_one_page(u_char *buffer, int length,
-                              unsigned long cr3, unsigned long addr, int rw)
+int
+pdb_change_page(u_char *buffer, int length,
+               unsigned long cr3, unsigned long addr, int rw)
 {
     l2_pgentry_t* l2_table = NULL;                         /* page directory */
     l1_pgentry_t* l1_table = NULL;                             /* page table */
@@ -980,10 +1170,11 @@ int pdb_change_values_one_page(u_char *buffer, int length,
     l2_table += l2_table_offset(addr);
     if (!(l2_pgentry_val(*l2_table) & _PAGE_PRESENT)) 
     {
-       if (pdb_page_fault_possible == 1)
+       if (pdb_page_fault_possible)
        {
            pdb_page_fault = 1;
-           TRC(printk("pdb: L2 error (0x%lx)\n", addr));
+           PDBTRC2(1,printk("pdb: expected L2 error %d (0x%lx)\n", 
+                            pdb_page_fault_possible, addr));
        }
        else
        {
@@ -1021,7 +1212,7 @@ int pdb_change_values_one_page(u_char *buffer, int length,
            if (pdb_page_fault_possible == 1)
            {
                pdb_page_fault = 1;
-               TRC(printk ("pdb: L1 error (0x%lx)\n", addr));
+               PDBTRC(1,printk ("pdb: L1 error (0x%lx)\n", addr));
            }
            else
            {
@@ -1038,18 +1229,25 @@ int pdb_change_values_one_page(u_char *buffer, int length,
 
     switch (rw)
     {
-    case __PDB_GET_VAL:                                              /* read */
+    case __PDB_GET:                                                  /* read */
+    {
         memcpy (buffer, page, length);
        bytes = length;
+
        break;
-    case __PDB_SET_VAL:                                             /* write */
-        hex2mem (buffer, page, length);
+    }
+    case __PDB_SET:                                                 /* write */
+    {
+        memcpy (page, buffer, length);
        bytes = length;
        break;
+    }
     default:                                                      /* unknown */
-        printk ("error: unknown RW flag: %d\n", rw);
+    {
+        printk ("pdb error: unknown RW flag: %d\n", rw);
        return 0;
     }
+    }
 
     unmap_domain_mem((void *)page); 
 exit1:
@@ -1061,9 +1259,146 @@ exit2:
     return bytes;
 }
 
+
+/***********************************************************************/
+/***********************************************************************/
+
+/* BREAKPOINTS */
+
+int
+pdb_set_breakpoint (pdb_bwcpoint_p bwc)
+{
+    pdb_read_memory (bwc->address, 1, &bwc->original, &bwc->context);
+    pdb_write_memory (bwc->address, 1, &pdb_x86_bkpt, &bwc->context);
+
+    pdb_bwc_list_add (bwc);
+
+    return 0;
+}
+
+int
+pdb_clear_breakpoint (unsigned long address, int length, pdb_context_p ctx)
+{
+    int error = 0;
+    pdb_bwcpoint_p bwc = pdb_bwc_list_search (address, 1, &pdb_ctx);
+
+    if (bwc == 0)
+    {
+      error = 3;                                     /* breakpoint not found */
+    }
+
+    pdb_write_memory (address, 1, &bwc->original, &pdb_ctx);
+    
+    pdb_bwc_list_remove (bwc);
+
+    return error;
+}
+
+/***********************************************************************/
 /***********************************************************************/
 
-void breakpoint(void);
+/* WATCHPOINTS */
+
+int pdb_process_watchpoint (pdb_bwcpoint_p bwc, pdb_generic_action action);
+
+int
+pdb_set_watchpoint (pdb_bwcpoint_p bwc)
+{
+    return pdb_process_watchpoint (bwc, __PDB_SET);
+}
+
+int
+pdb_clear_watchpoint (pdb_bwcpoint_p bwc)
+{
+    return pdb_process_watchpoint (bwc, __PDB_CLEAR);
+}
+
+/* set or clear watchpoint */
+int
+pdb_process_watchpoint (pdb_bwcpoint_p bwc, pdb_generic_action action)
+{
+    int return_value;
+    pdb_invoke_args_t args;
+
+    args.context = &bwc->context;
+    args.address = bwc->address;
+    args.length = bwc->length;
+    args.data = bwc;
+    switch (bwc->type)
+    {
+    case PDB_WP_WRITE :
+    {
+        args.action = (action == __PDB_SET) ? PDB_BWC_PAGE_WRITE_SET 
+                                            : PDB_BWC_PAGE_WRITE_CLEAR;
+       break;       
+    }
+    case PDB_WP_READ :
+    {
+        args.action = (action == __PDB_SET) ? PDB_BWC_PAGE_READ_SET 
+                                            : PDB_BWC_PAGE_READ_CLEAR;
+       break;       
+    }
+    case PDB_WP_ACCESS :
+    {
+        args.action = (action == __PDB_SET) ? PDB_BWC_PAGE_ACCESS_SET 
+                                            : PDB_BWC_PAGE_ACCESS_CLEAR;
+       break;       
+    }
+    default :
+    {
+        printk ("pdb error: incorrect watchpoint type [%d][%s]",
+               bwc->type, pdb_bwcpoint_type_s[bwc->type]);
+        break;
+    }
+    }
+
+    return_value = pdb_invoke (pdb_bwc_page, &args);
+
+    if (return_value < 0)
+    {
+         strcpy (pdb_out_buffer, "E03");
+    }
+
+    return return_value;
+}
+
+/*
+ * set or clear watchpoint for a single page 
+ */
+
+int 
+pdb_bwc_page (int action, unsigned long addr, int length, 
+             pdb_context_p ctx, int offset, void *data)
+{
+    int rval = 0;
+
+    printk ("bwc: %s [0x%08lx:%x] 0x%x (0x%p)\n",
+           pdb_bwc_page_action_s[action], addr, length, offset, data);
+
+    switch (action)
+    {
+    case PDB_BWC_PAGE_ACCESS_SET :
+    case PDB_BWC_PAGE_ACCESS_CLEAR : 
+    case PDB_BWC_PAGE_WRITE_SET :
+    case PDB_BWC_PAGE_WRITE_CLEAR :
+    case PDB_BWC_PAGE_READ_SET :
+    case PDB_BWC_PAGE_READ_CLEAR :
+    {
+        printk ("fill in the blank [%s:%d]\n", __FILE__, __LINE__);
+        break;
+    }
+    default :
+    {
+        printk ("pdb error: unknown bwc page action [%d]\n", action);
+       break;
+    }
+    }
+
+    return rval;
+}
+
+/***********************************************************************/
+/***********************************************************************/
 
 /* send the packet in buffer.  */
 void pdb_put_packet (unsigned char *buffer, int ack)
@@ -1114,7 +1449,7 @@ void pdb_get_packet(char *buffer)
        count = 0;
        checksum = 0;
 
-       while (count < BUFMAX)
+       while (count < PDB_BUFMAX)
        {
            ch = pdb_get_char();
            if (ch  == '#') break;
@@ -1132,10 +1467,11 @@ void pdb_get_packet(char *buffer)
            if (xmitcsum == checksum)
            {
                pdb_put_char('+');
+
+#ifdef GDB_50_SUPPORT
                if (buffer[2] == ':')
-               {
-                   printk ("pdb: obsolete gdb packet (sequence ID)\n");
-               }
+                 { printk ("pdb: obsolete gdb packet (sequence ID)\n"); }
+#endif
            }
            else
            {
@@ -1157,22 +1493,34 @@ int pdb_handle_exception(int exceptionVector,
                         struct pt_regs *xen_regs)
 {
     int signal = 0;
-    struct pdb_breakpoint* bkpt;
+    struct pdb_bwcpoint* bkpt;
     int watchdog_save;
     unsigned long cr3;
 
     __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
 
+PDBTRC(4,printk("pdb handle exception\n"));
+PDBTRC(4,printk("    cr3: 0x%lx\n", cr3));
+PDBTRC(4,printk("    eip: 0x%lx\n", xen_regs->eip));
+PDBTRC(4,printk("    except vector: 0x%x\n", exceptionVector));
+PDBTRC(4,printk("    xcs: 0x%x\n", xen_regs->xcs));
+PDBTRC(4,printk("    sys call next addr: 0x%lx\n", pdb_system_call_next_addr));
+PDBTRC(4,printk("    stepping: 0x%x\n", pdb_stepping));
+PDBTRC(4,printk("    system_call: 0x%x\n", pdb_system_call));
+
     /* If the exception is an int3 from user space then pdb is only
        interested if it re-wrote an instruction set the breakpoint.
        This occurs when leaving a system call from a domain.
     */
-    if ( exceptionVector == 3 &&
+    bkpt = pdb_bwcpoint_search(cr3, xen_regs->eip - 1);
+    if ( bkpt == NULL &&
+         exceptionVector == 3 &&
         (xen_regs->xcs & 3) == 3 && 
         xen_regs->eip != pdb_system_call_next_addr + 1)
     {
-        TRC(printf("pdb: user bkpt (0x%x) at 0x%x:0x%lx:0x%lx\n", 
-                  exceptionVector, xen_regs->xcs & 3, cr3, xen_regs->eip));
+        PDBTRC(1,printk("pdb: user bkpt (0x%x) at 0x%x:0x%lx:0x%lx 0x%lx\n", 
+                       exceptionVector, xen_regs->xcs & 3, cr3, 
+                       xen_regs->eip, pdb_system_call_next_addr));
        return 1;
     }
 
@@ -1182,7 +1530,6 @@ int pdb_handle_exception(int exceptionVector,
      * the user didn't press the magic debug key, 
      * then we don't handle the exception.
      */
-    bkpt = pdb_bkpt_search(cr3, xen_regs->eip - 1);
     if ( (bkpt == NULL) &&
          !pdb_stepping && 
         !pdb_system_call &&
@@ -1190,8 +1537,8 @@ int pdb_handle_exception(int exceptionVector,
         (exceptionVector != KEYPRESS_EXCEPTION) &&
         xen_regs->eip < 0xc0000000)  /* Linux-specific for now! */
     {
-        TRC(printf("pdb: user bkpt (0x%x) at 0x%lx:0x%lx\n", 
-                  exceptionVector, cr3, xen_regs->eip));
+        PDBTRC(1,printk("pdb: user bkpt (0x%x) at 0x%lx:0x%lx\n", 
+                    exceptionVector, cr3, xen_regs->eip));
        return 1;
     }
 
@@ -1222,22 +1569,23 @@ int pdb_handle_exception(int exceptionVector,
        }
     }
 
-    if ( exceptionVector == BREAKPT_EXCEPTION && bkpt != NULL)
-    {
-        /* Executed Int3: replace breakpoint byte with real program byte. */
-        xen_regs->eip--;
-    }
-
     /* returning to user space after a system call */
     if ( xen_regs->eip == pdb_system_call_next_addr + 1)
     {
-        u_char instr[2];                      /* REALLY REALLY REALLY STUPID */
-
-       mem2hex (&pdb_system_call_leave_instr, instr, sizeof(instr)); 
-
-       pdb_linux_set_values (instr, 1, pdb_system_call_next_addr,
-                             pdb_ctx.process, pdb_ctx.ptbr);
-
+        printk("BUG ******** \n");
+         printk("BUG return to user space bug\n");
+        printk("BUG ******** \n");
+
+        /*
+        * BUG: remember to delete the breakpoint!!!
+        *       
+        */
+
+        /* this is always in a process context */
+        pdb_write_memory (pdb_system_call_next_addr,
+                         sizeof(pdb_system_call_leave_instr),
+                         &pdb_system_call_leave_instr, &pdb_ctx);
        pdb_system_call_next_addr = 0;
        pdb_system_call_leave_instr = 0;
 
@@ -1253,6 +1601,13 @@ int pdb_handle_exception(int exceptionVector,
        }
     }
 
+
+    if ( exceptionVector == BREAKPT_EXCEPTION && bkpt != NULL)
+    {
+        /* Executed Int3: replace breakpoint byte with real program byte. */
+        xen_regs->eip--;
+    }
+
     /* Generate a signal for GDB. */
     switch ( exceptionVector )
     {
@@ -1303,9 +1658,6 @@ void initialize_pdb()
 {
     extern char opt_pdb[];
 
-    /* Certain state must be initialised even when PDB will not be used. */
-    memset((void *) &breakpoints, 0, sizeof(breakpoints));
-    INIT_LIST_HEAD(&breakpoints.list);
     pdb_stepping = 0;
 
     if ( strcmp(opt_pdb, "none") == 0 )
@@ -1335,8 +1687,6 @@ void initialize_pdb()
     pdb_initialized = 1;
 }
 
-void breakpoint(void)
-{
-    if ( pdb_initialized )
-        asm("int $3");
-}
+/***********************************************************************/
+/***********************************************************************/
+
index 557997be3f5830e3d451e55c23e2e6bb552b84eb..92135ceecc15745c3f2909676d3053e6372d70e9 100644 (file)
@@ -45,7 +45,7 @@ static inline unsigned long machine_to_phys(unsigned long cr3,
                                             unsigned long machine)
 {
   unsigned long phys;
-  pdb_get_values((u_char *) &phys, sizeof(phys), cr3,
+  pdb_read_page((u_char *) &phys, sizeof(phys), cr3,
                 (unsigned long) machine_to_phys_mapping + 
                  (machine >> PAGE_SHIFT) * 4);
   phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
@@ -75,20 +75,20 @@ unsigned long pdb_linux_pid_task_struct (unsigned long cr3, int pid)
   unsigned long task_struct_pid;
 
   /* find the task_struct of the given process */
-  pdb_get_values((u_char *) &task_struct_p, sizeof(task_struct_p),
+  pdb_read_page((u_char *) &task_struct_p, sizeof(task_struct_p),
                 cr3, pdb_pidhash_addr + pid_hashfn(pid) * 4);
 
   /* find the correct task struct */
   while (task_struct_p != (unsigned long)NULL)
   {
-    pdb_get_values((u_char *) &task_struct_pid, sizeof(task_struct_pid),
+    pdb_read_page((u_char *) &task_struct_pid, sizeof(task_struct_pid),
                   cr3, task_struct_p + task_struct_pid_offset);
     if (task_struct_pid == pid)
     {
       break;
     }
 
-    pdb_get_values((u_char *) &task_struct_p, sizeof(task_struct_p),
+    pdb_read_page((u_char *) &task_struct_p, sizeof(task_struct_p),
                   cr3, task_struct_p + task_struct_pidhash_next_offset);
   }
   if (task_struct_p == (unsigned long) NULL)
@@ -116,96 +116,59 @@ unsigned long pdb_linux_pid_ptbr (unsigned long cr3, int pid)
   }
 
   /* get the mm_struct within the task_struct */
-  pdb_get_values((u_char *) &mm_p, sizeof(mm_p),
+  pdb_read_page((u_char *) &mm_p, sizeof(mm_p),
                 cr3, task_struct_p + task_struct_mm_offset);
   /* get the page global directory (cr3) within the mm_struct */
-  pdb_get_values((u_char *) &pgd, sizeof(pgd),
+  pdb_read_page((u_char *) &pgd, sizeof(pgd),
                 cr3, mm_p + mm_struct_pgd_offset);
 
   return pgd;
 }
 
 
+/* read / write values from one page */
 
-/* read a byte from a process 
- *
- * in: pid: process id
- *     cr3: ptbr for the process' domain
- *     addr: address to read
- */
-
-u_char pdb_linux_get_value(int pid, unsigned long cr3, unsigned long addr)
-{
-  u_char result = 0;
-  unsigned long pgd;
-  unsigned long l2tab, page;
-
-  /* get the process' pgd */
-  pgd = pdb_linux_pid_ptbr(cr3, pid);
-
-  /* get the l2 table entry */
-  pdb_get_values((u_char *) &l2tab, sizeof(l2tab),
-                cr3, pgd + (addr >> PGDIR_SHIFT) * 4);
-  l2tab = (unsigned long)__va(machine_to_phys(cr3, l2tab) & PAGE_MASK);
-
-  /* get the page table entry */
-  pdb_get_values((u_char *) &page, sizeof(page),
-                cr3, l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4);
-  page = (unsigned long)__va(machine_to_phys(cr3, page) & PAGE_MASK);
-
-  /* get the byte */
-  pdb_get_values((u_char *) &result, sizeof(result),
-                cr3, page + (addr & ~PAGE_MASK));
-
-  return result;
-}
-
-void pdb_linux_get_values(char *buffer, int length, unsigned long address,
-                         int pid, unsigned long cr3)
-{
-    int loop;
-
-    /* yes, this can be optimized... a lot */
-    for (loop = 0; loop < length; loop++)
-    {
-        buffer[loop] = pdb_linux_get_value(pid, cr3, address + loop);
-    }
-}
-
-void pdb_linux_set_value(int pid, unsigned long cr3, unsigned long addr,
-                        u_char *value)
+u_char 
+pdb_linux_visit_page(int pid, unsigned long cr3, unsigned long addr,
+                    int length, unsigned char *buffer, int action)
 {
+    u_char result = 0;
     unsigned long pgd;
     unsigned long l2tab, page;
+
     /* get the process' pgd */
     pgd = pdb_linux_pid_ptbr(cr3, pid);
+
     /* get the l2 table entry */
-    pdb_get_values((u_char *) &l2tab, sizeof(l2tab),
-                  cr3, pgd + (addr >> PGDIR_SHIFT) * 4);
+    pdb_read_page((u_char *) &l2tab, sizeof(l2tab),
+                 cr3, pgd + (addr >> PGDIR_SHIFT) * 4);
     l2tab = (unsigned long)__va(machine_to_phys(cr3, l2tab) & PAGE_MASK);
+
     /* get the page table entry */
-    pdb_get_values((u_char *) &page, sizeof(page),
-                  cr3, l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4);
+    pdb_read_page((u_char *) &page, sizeof(page),
+                 cr3, l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4);
     page = (unsigned long)__va(machine_to_phys(cr3, page) & PAGE_MASK);
-    /* set the byte */
-    pdb_set_values(value, sizeof(u_char), cr3, page + (addr & ~PAGE_MASK));
-}
-void pdb_linux_set_values(char *buffer, int length, unsigned long address,
-                         int pid, unsigned long cr3)
-{
-    int loop;
-    /* it's difficult to imagine a more inefficient algorithm */
-    for (loop = 0; loop < length; loop++)
+
+    switch (action)
     {
-        pdb_linux_set_value(pid, cr3, address + loop, &buffer[loop * 2]);
+    case __PDB_GET :
+    {
+        pdb_read_page(buffer, length, cr3, page + (addr & ~PAGE_MASK));
+        break;
+    }
+    case __PDB_SET :
+    {
+        pdb_write_page(buffer, length, cr3, page + (addr & ~PAGE_MASK));
+        break;
     }
+    default :
+    {
+        printk ("pdb error: linux_visit_page unknown action [%d]\n", action);
+       break;
+    }
+    }
+
+    return result;
 }
 
 /**********************************************************************/
@@ -232,18 +195,18 @@ int pdb_linux_process_list (unsigned long cr3, int array[], int max)
   int count = 0;
 
   /* task_p = init_task->next_task  */
-  pdb_get_values((u_char *) &task_p, sizeof(task_p),
+  pdb_read_page((u_char *) &task_p, sizeof(task_p),
                 cr3, pdb_init_task_union_addr + task_struct_next_task_offset);
   
   while (task_p != pdb_init_task_union_addr)
   {
-      pdb_get_values((u_char *) &pid, sizeof(pid),
+      pdb_read_page((u_char *) &pid, sizeof(pid),
                     cr3, task_p + task_struct_pid_offset);
 
       array[count % max] = pid;
       count++;
 
-      pdb_get_values((u_char *) &next_p, sizeof(next_p),
+      pdb_read_page((u_char *) &next_p, sizeof(next_p),
                     cr3, task_p + task_struct_next_task_offset);
       task_p = next_p;
   }
@@ -260,7 +223,7 @@ void pdb_linux_process_details (unsigned long cr3, int pid, char *buffer)
 
   task_struct_p = pdb_linux_pid_task_struct(cr3, pid);
 
-  pdb_get_values((u_char *) buffer, task_struct_comm_length,
+  pdb_read_page((u_char *) buffer, task_struct_comm_length,
                 cr3, task_struct_p + task_struct_comm_offset);
   return;
 }
index b17748a864b70f21fe52f12098e84573d558027c..9ea4746934745b69ddc5dac77170eece8eebccae 100644 (file)
@@ -65,7 +65,7 @@ void pdb_do_debug (dom0_op_t *op)
         case 'r' :
         {
             int loop;
-            u_char x;
+            u_char x = 0;
            unsigned long cr3;
            struct domain *d;
 
@@ -81,8 +81,8 @@ void pdb_do_debug (dom0_op_t *op)
                 {
                     printk ("\n%08x ", op->u.debug.in1 + loop);
                 }
-                x = pdb_linux_get_value(op->u.debug.in3,
-                                       cr3, op->u.debug.in1 + loop);
+               /* x = pdb_linux_get_value(op->u.debug.in3,
+                  cr3, op->u.debug.in1 + loop); */
                 printk (" %02x", x);
             }
             printk ("\n");
index 2ed6a9a3187d38b6ecdbd5e6f997e13be0569b89..d33d5570fbaa081222ad42df0d15749190df5fd1 100644 (file)
@@ -26,11 +26,30 @@ extern int pdb_page_fault;
 
 extern void initialize_pdb(void);
 
-/* Get/set values from generic debug interface. */
-extern int pdb_set_values(u_char *buffer, int length,
-                          unsigned long cr3, unsigned long addr);
-extern int pdb_get_values(u_char *buffer, int length,
-                          unsigned long cr3, unsigned long addr);
+/*
+ * pdb debug context 
+ */
+typedef struct pdb_context
+{
+    int valid;
+    int domain;
+    int process;
+    int system_call;              /* 0x01 break on enter, 0x02 break on exit */
+    unsigned long ptbr;
+} pdb_context_t, *pdb_context_p;
+
+extern pdb_context_t pdb_ctx;
+
+/* read / write memory */
+extern int pdb_read_memory (unsigned long addr, int length, 
+                           unsigned char *data, pdb_context_p ctx);
+extern int pdb_write_memory (unsigned long addr, int length, 
+                            unsigned char *data, pdb_context_p ctx);
+
+extern int pdb_read_page (u_char *buffer, int length,
+                         unsigned long cr3, unsigned long addr);
+extern int pdb_write_page (u_char *buffer, int length,
+                          unsigned long cr3, unsigned long addr);
 
 /* External entry points. */
 extern int pdb_handle_exception(int exceptionVector,
@@ -38,29 +57,47 @@ extern int pdb_handle_exception(int exceptionVector,
 extern int pdb_serial_input(u_char c, struct pt_regs *regs);
 extern void pdb_do_debug(dom0_op_t *op);
 
-/* PDB Context. */
-struct pdb_context
+typedef enum pdb_generic_action
 {
-    int valid;
-    int domain;
-    int process;
-    int system_call;              /* 0x01 break on enter, 0x02 break on exit */
-    unsigned long ptbr;
-};
-extern struct pdb_context pdb_ctx;
+  __PDB_GET,
+  __PDB_SET,
+  __PDB_CLEAR
+} pdb_generic_action;
 
-/* Breakpoints. */
-struct pdb_breakpoint
+/*
+ * breakpoint, watchpoint, & catchpoint
+ * note: numbers must match GDB remote serial protocol Z command numbers
+ */
+enum pdb_bwcpoint_type
 {
-    struct list_head list;
-    unsigned long address;
-    unsigned long cr3;
-    domid_t domain;
+  PDB_BP_SOFTWARE = 0,
+  PDB_BP_HARDWARE = 1,
+  PDB_WP_WRITE    = 2,
+  PDB_WP_READ     = 3,
+  PDB_WP_ACCESS   = 4
 };
-extern void pdb_bkpt_add (unsigned long cr3, unsigned long address);
-extern struct pdb_breakpoint* pdb_bkpt_search (unsigned long cr3, 
-                                              unsigned long address);
-extern int pdb_bkpt_remove (unsigned long cr3, unsigned long address);
+
+typedef struct pdb_bwcpoint
+{
+  struct list_head list;
+  unsigned long address;
+  int length;
+  enum pdb_bwcpoint_type type;                            /* how implemented */
+  enum pdb_bwcpoint_type user_type;                    /* what was requested */
+  pdb_context_t context;
+
+  /* original value for breakpoint, one byte for x86 */
+  unsigned char original;
+} pdb_bwcpoint_t, *pdb_bwcpoint_p;
+
+void pdb_bwc_list_add (pdb_bwcpoint_p bwc);
+void pdb_bwc_list_remove (pdb_bwcpoint_p bwc);
+pdb_bwcpoint_p pdb_bwcpoint_search (unsigned long cr3, unsigned long address);
+
+int pdb_set_breakpoint (pdb_bwcpoint_p bwc);
+int pdb_clear_breakpoint (unsigned long address, int length, 
+                         pdb_context_p ctx);
+
 
 /* Conversions. */
 extern int   hex (char);
@@ -85,4 +122,10 @@ void pdb_linux_syscall_enter_bkpt (struct pt_regs *regs, long error_code,
 void pdb_linux_syscall_exit_bkpt (struct pt_regs *regs, 
                                  struct pdb_context *pdb_ctx);
 
+/* tracing */
+extern int pdb_trace;
+#define PDBTRC(_lvl_, _blahblah_) if (_lvl_ & pdb_trace) {_blahblah_;}
+#define PDBTRC2(_lvl_, _blahblah_) \
+  if (_lvl_ & pdb_trace) {printk("[%s:%d]",__FILE__,__LINE__); _blahblah_;}
+
 #endif  /* __PDB_H__ */